package com.demo.weather.server;

import com.demo.weather.server.handler.DecodeHandler;
import com.demo.weather.server.handler.EncodeHandler;
import com.demo.weather.server.handler.PacketDataHandler;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class AbstractServer implements WeatherServer {
	
	public static final String HANDLER_NAME_TRYWAKEUP = "TRYWAKEUP";
    public static final String HANDLER_NAME_READ_TIMEOUT = "READ_TIMEOUT";
    public static final String HANDLER_NAME_DECODER = "INBOUND_DECODER";
    public static final String HANDLER_NAME_ENCODER = "OUTBOUND_ENCODER";
    public static final String HANDLER_NAME_SESSION = "SESSION";
    public static final String HANDLER_NAME_AUTH = "AUTH";
    public static final String HANDLER_NAME_PACKET = "PACKET";

    protected EventLoopGroup boss = new NioEventLoopGroup();
    protected EventLoopGroup worker = new NioEventLoopGroup();
    protected ChannelFuture channelFuture;
    
    private EncodeHandler encodeHandler;
    private PacketDataHandler packetHandler;

    protected WeatherServerProperties serverProperties;

    public AbstractServer(EncodeHandler encodeHandler, PacketDataHandler packetHandler,
			WeatherServerProperties serverProperties) {
		this.encodeHandler = encodeHandler;
		this.packetHandler = packetHandler;
		this.serverProperties = serverProperties;
	}

	@Override
    public boolean run() {
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss, worker);
            serverBootstrap.channel(NioServerSocketChannel.class);

            setupServerBootstrap(serverBootstrap);

            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline channelPipeline = socketChannel.pipeline();
                    
                    // 超时处理器
                    addTimeoutHandler(channelPipeline);

                    // 编码、解码的处理器
                    addCodecHandler(channelPipeline);
                    
                    // 业务代码处理器
                    addServerHandler(channelPipeline);
                }
            });

            channelFuture = serverBootstrap.bind(serverProperties.getPort()).sync();
        } catch (Exception e) {
            log.error("start emb server failed. port={}", serverProperties.getPort(), e);
            throw new RuntimeException(e);
        }

        return true;
    }

    protected void setupServerBootstrap(ServerBootstrap serverBootstrap) {
    }

    protected void addTimeoutHandler(ChannelPipeline channelPipeline) {
        
    }

    protected void addCodecHandler(ChannelPipeline channelPipeline) {
    	channelPipeline.addLast(HANDLER_NAME_DECODER, new DecodeHandler());
        channelPipeline.addLast(HANDLER_NAME_ENCODER, encodeHandler);
    }
    
    protected void addServerHandler(ChannelPipeline channelPipeline) {
        channelPipeline.addLast(HANDLER_NAME_PACKET, packetHandler);
    }

    @Override
    public boolean shutdown() {
    	if(null == channelFuture) {
            return true;
        }

		try {
			channelFuture.channel().close().awaitUninterruptibly(); //.closeFuture().sync();
		} catch (Exception e) {
			log.error("shutdown exception", e);
		} finally {
			try {
				worker.shutdownGracefully();
			} catch (Exception e) {
				log.error("", e);
			}
			try {
				boss.shutdownGracefully();
			} catch (Exception e) {
				log.error("", e);
			}
			log.info("Server is shutdown gracefully!port={}", serverProperties.getPort());
		}

        return true;
    }
}